///PHILOTES Source Code.  (C)2012 PhiloLabs
#pragma once

#ifndef __RenderTarget_H__
#define __RenderTarget_H__

#include "OgrePrerequisites.h"

#include "OgreString.h"
#include "OgreTextureManager.h"
#include "OgreViewport.h"
#include "timing/timer.h"

/* Define the number of priority groups for the render system's render targets. */
#ifndef OGRE_NUM_RENDERTARGET_GROUPS
	#define OGRE_NUM_RENDERTARGET_GROUPS 10
	#define OGRE_DEFAULT_RT_GROUP 4
	#define OGRE_REND_TO_TEX_RT_GROUP 2
#endif

namespace Ogre {

	
	
	
    class _OgreExport RenderTarget : public MemAlloc_RenderSys
    {
    public:
        enum StatFlags
        {
            SF_NONE           = 0,
            SF_FPS            = 1,
            SF_AVG_FPS        = 2,
            SF_BEST_FPS       = 4,
            SF_WORST_FPS      = 8,
            SF_TRIANGLE_COUNT = 16,
            SF_ALL            = 0xFFFF
        };

        struct FrameStats
        {
            float lastFPS;
            float avgFPS;
            float bestFPS;
            float worstFPS;
            unsigned long bestFrameTime;
            unsigned long worstFrameTime;
            size_t triangleCount;
            size_t batchCount;
        };

		enum FrameBuffer
		{
			FB_FRONT,
			FB_BACK,
			FB_AUTO
		};

        RenderTarget();
        virtual ~RenderTarget();

        /// Retrieve target's name.
        virtual const String& getName(void) const;

        /// Retrieve information about the render target.
        virtual void getMetrics(unsigned int& width, unsigned int& height, unsigned int& colourDepth);

        virtual unsigned int getWidth(void) const;
        virtual unsigned int getHeight(void) const;
        virtual unsigned int getColourDepth(void) const;

		/**
		 * Sets the pool ID this RenderTarget should query from. Default value is POOL_DEFAULT.
		 * Set to POOL_NO_DEPTH to avoid using a DepthBuffer (or manually controlling it) @see DepthBuffer
		 *	@remarks
		 *		Changing the pool Id will cause the current depth buffer to be detached unless the old
		 *		id and the new one are the same
		 */
		void setDepthBufferPool( uint16 poolId );

		//Returns the pool ID this RenderTarget should query from. @see DepthBuffer
		uint16 getDepthBufferPool() const;

		DepthBuffer* getDepthBuffer() const;

		//Returns false if couldn't attach
		virtual bool attachDepthBuffer( DepthBuffer *depthBuffer );

		virtual void detachDepthBuffer();

		
		virtual void _detachDepthBuffer();

        
        virtual void update(bool swapBuffers = true);
        
        virtual void swapBuffers(bool waitForVSync = true)
        { (void)waitForVSync; }

        
        virtual Viewport* addViewport(Camera* cam, int ZOrder = 0, float left = 0.0f, float top = 0.0f ,
            float width = 1.0f, float height = 1.0f);

        
        virtual unsigned short getNumViewports(void) const;

        
        virtual Viewport* getViewport(unsigned short index);

		
        virtual Viewport* getViewportByZOrder(int ZOrder);

		
		virtual bool hasViewportWithZOrder(int ZOrder);

        
        virtual void removeViewport(int ZOrder);

        
        virtual void removeAllViewports(void);

        
        virtual void getStatistics(float& lastFPS, float& avgFPS,
            float& bestFPS, float& worstFPS) const;  // Access to stats

        virtual const FrameStats& getStatistics(void) const;

        
        virtual float getLastFPS() const;

        
        virtual float getAverageFPS() const;

        
        virtual float getBestFPS() const;

        
        virtual float getWorstFPS() const;

        
        virtual float getBestFrameTime() const;

        
        virtual float getWorstFrameTime() const;

        
        virtual void resetStatistics(void);

        
        virtual void getCustomAttribute(const String& name, void* pData);

        
        virtual void addListener(RenderTargetListener* listener);
        
        virtual void removeListener(RenderTargetListener* listener);
        
        virtual void removeAllListeners(void);

		
        virtual void setPriority( uchar priority ) { mPriority = priority; }
        
		virtual uchar getPriority() const { return mPriority; }

        
        virtual bool isActive() const;

        
        virtual void setActive( bool state );

        
        virtual void setAutoUpdated(bool autoupdate);
        
        virtual bool isAutoUpdated(void) const;

		
		virtual void copyContentsToMemory(const PixelBox &dst, FrameBuffer buffer = FB_AUTO) = 0;

		
		virtual PixelFormat suggestPixelFormat() const { return PF_BYTE_RGBA; }
		
        
        void writeContentsToFile(const String& filename);

		
		virtual String writeContentsToTimestampedFile(const String& filenamePrefix, const String& filenameSuffix);

		virtual bool requiresTextureFlipping() const = 0;

		
		virtual size_t getTriangleCount(void) const;
        
		virtual size_t getBatchCount(void) const;
        
        virtual void _notifyCameraRemoved(const Camera* cam);

        
        virtual bool isPrimary(void) const;

		
		virtual bool isHardwareGammaEnabled() const { return mHwGamma; }

		
		virtual uint getFSAA() const { return mFSAA; }

		
		virtual const String& getFSAAHint() const { return mFSAAHint; }

        
        class Impl
        {
        protected:
            ~Impl() { }
        };
        
        virtual Impl *_getImpl();

		
		virtual void _beginUpdate();

		
		virtual void _updateViewport(int zorder, bool updateStatistics = true);

		
		virtual void _updateViewport(Viewport* viewport, bool updateStatistics = true);

		
		virtual void _updateAutoUpdatedViewports(bool updateStatistics = true);
		
		
		virtual void _endUpdate();

    protected:
        /// The name of this target.
        String mName;
		/// The priority of the render target.
		uchar mPriority;

        unsigned int mWidth;
        unsigned int mHeight;
        unsigned int mColourDepth;
		uint16		 mDepthBufferPoolId;
        DepthBuffer	*mDepthBuffer;

        // Stats
		FrameStats mStats;
        
        Timing::PhiloTimer* mTimer ;
        unsigned long mLastSecond;
        unsigned long mLastTime;
        size_t mFrameCount;

        bool mActive;
        bool mAutoUpdate;
		// Hardware sRGB gamma conversion done on write?
		bool mHwGamma;
		// FSAA performed?
		uint mFSAA;
		String mFSAAHint;

        void updateStats(void);

		typedef map<int, Viewport*>::type ViewportList;
        /// List of viewports, map on Z-order
        ViewportList mViewportList;

        typedef vector<RenderTargetListener*>::type RenderTargetListenerList;
        RenderTargetListenerList mListeners;
	

        /// internal method for firing events
        virtual void firePreUpdate(void);
        /// internal method for firing events
        virtual void firePostUpdate(void);
        /// internal method for firing events
        virtual void fireViewportPreUpdate(Viewport* vp);
        /// internal method for firing events
        virtual void fireViewportPostUpdate(Viewport* vp);
		/// internal method for firing events
		virtual void fireViewportAdded(Viewport* vp);
		/// internal method for firing events
		virtual void fireViewportRemoved(Viewport* vp);
		
		/// Internal implementation of update()
		virtual void updateImpl();
    };
	
	

} // Namespace

#endif
